/*
    buffer是缓冲区的意思，有readindex和writeindex两个指针，分别指示读到了哪里和写到了哪里，retrieve本意是
    归还，但我们是对缓冲区操作，所以这个归还实际上就是把缓冲区中的一部分空间拿走，也就是内存回收的意思，
    这个回收的实现我们是直接把readindex指针后移。如果直接回收到了write_index_处，说明缓冲区中内容全读完了，那就把read
    和write指针收回到kPrePendIndex处即可。
    peek则是把东西拿走，但指针不动，peek仅仅是看一眼缓冲区中的内容，对指针没有影响。
    然后buffer默认从kPrePendIndex处开始读写，buffer不够用了就加空间(不过有限制最大大小)，用满了重新把两个指针
    挪回kPrePendIndex处即可。 
    底层实质上是一个vector，它的内存扩展之类的机制都和vector一致
    总的来说实现非常简单，很容易理解
*/

#ifndef TINY_MUDUO_BUFFER_H
#define TINY_MUDUO_BUFFER_H

#include<vector>
#include<algorithm>
#include<string>
#include<assert.h>

using std::string;

namespace tiny_muduo{
    static const int kPrePendIndex=8;

    class Buffer{
        public:
            Buffer():buffer_(1024),read_index_(kPrePendIndex),write_index_(kPrePendIndex){}
            ~Buffer(){}

            int ReadFd(int fd);

            char* begin(){return &*buffer_.begin();} //这里用的其实是vector的begin函数
            const char* begin() const{return &* buffer_.begin();}
            //写两个函数，一个常量函数一个非常量函数，这是因为非常量成员既可以访问常量函数又可以访问非常量函数
            //但常量成员只能访问常量函数，为了防止常亮成员访问出现问题，写两个函数，这是一种很常见的做法
            //(你问我为什么不直接只写一个常量函数？ 我只能说约定俗成)

            char* beginread(){return begin()+read_index_;}
            const char* beginread() const{return begin()+read_index_;}

            char* beginwrite(){return begin()+write_index_;}
            const char* beginwrite() const{return begin()+write_index_;}

            void Append(const char* message,int len){
                MakeSureEnoughStorage(len);
                std::copy(message,message+len,beginwrite());
                write_index_+=len;
            }

            void Append(const string& message){
                Append(message.data(),message.size());
            }

            void Retrieve(int len){
                if(len+read_index_!=write_index_){
                    read_index_=read_index_+len;
                }else{ //意思是直接读到头了，就等于全读完了，全读完就直接从头开始呗，内存全部收回
                    write_index_=kPrePendIndex;
                    read_index_=write_index_;
                }
            }

            void RetrieveUntilIndex(const char* index){
                assert(beginwrite()>=index); //index要比写进去的内容小
                read_index_+=index-beginread();//这里扩展开就是read_index_=index+begin(),是加上index和当前read指针的差值
            }

            void RetrieveAll(){//回收完
                write_index_=kPrePendIndex;
                read_index_=write_index_;
            }

            string RetrieveAsString(int len){
                assert(read_index_+len<=write_index_);
                string ret=std::move(PeekAsString(len));//move这个函数还用到了右值引用相关的知识，可以了解一下
                Retrieve(len);
                return ret;
            }


            string RetrieveAllAsString() {
                string ret = std::move(PeekAllAsString());
                RetrieveAll();
                return ret;
            }

            const char* Peek() const{
                return beginread();
            }

            char* Peek(){
                return beginread();
            }

            string PeekAsString(int len){
                return string(beginread(),beginread()+len);
            }

            string PeekAllAsString(){
                return string(beginread(),beginwrite());
            }

            int readablebytes() const{return write_index_-read_index_;}
            int writeablebytes() const{return buffer_.capacity()-write_index_;}
            int prependablebytes() const{return read_index_;}
        //prepend表示可以在缓冲区头部 预添加的大小，这个大小其实就是缓冲区不用的大小，缓冲区从0到read_index之间的部分是不用的，可以用来放头部信息

            void MakeSureEnoughStorage(int len){ //确保大小够用，功能很简单一看就懂
                if(writeablebytes()>=len) return;
                if(writeablebytes()+prependablebytes()>=kPrePendIndex+len){
                    std::copy(beginread(),beginwrite(),begin()+kPrePendIndex);
                    write_index_=8+readablebytes();
                    read_index_=8;
                }else{
                    buffer_.resize(buffer_.size()+len);
                }
            }
        private:
        std::vector<char> buffer_;
        int read_index_;
        int write_index_;
    };
}

#endif